home *** CD-ROM | disk | FTP | other *** search
- /* MEMORY.C
- ************************************************************************
- * *
- * PC Scheme/Geneva 4.00 Borland C code *
- * *
- * (c) 1985-1988 by Texas Instruments, Inc. See COPYRIGHT.TXT *
- * (c) 1992 by L. Bartholdi & M. Vuilleumier, University of Geneva *
- * *
- *----------------------------------------------------------------------*
- * *
- * Allocate Space in a Scheme Page *
- * *
- *----------------------------------------------------------------------*
- * *
- * Created by: John Jensen Date: 1985 *
- * Revision history: *
- * - 18 Jun 92: Renaissance (Borland Compilers, ...) *
- * - 20 Jan 93: REG class created for automatic gc management (mv) *
- * *
- * ``In nomine omnipotentii dei'' *
- ************************************************************************/
-
- #include <string.h>
- #include <stdlib.h>
- #include <conio.h>
- #include "scheme.h"
-
- /************************************************************************/
- /* Allocate a Page in Scheme's Memory */
- /************************************************************************/
- unsigned alloc_page(unsigned type, unsigned minsize)
- {
- int newpage, previous = END_LIST;
-
- for( newpage = freepage; newpage != END_LIST; previous = newpage, newpage = pagelink[newpage] )
- if( psize[newpage] >= minsize )
- {
- if( previous == END_LIST )
- freepage = pagelink[newpage];
- else pagelink[previous] = pagelink[newpage];
- break;
- }
- if( newpage == END_LIST ) /* failure: no page big enough */
- return END_LIST;
-
- /* Define page management characteristics for this type page */
- attrib[newpage] = pageattr[type/2];
- pagelink[newpage] = pagelist[type/2];
- ptype[newpage] = type;
- pagelist[type/2] = newpage;
-
- zero_page(newpage);
-
- /* Initialize free storage chains for appropriate data type */
- switch (type)
- {
- case LISTTYPE:
- case FLOTYPE:
- swpage(newpage);
- break;
-
- case BIGTYPE:
- case SYMTYPE:
- case STRTYPE:
- case I86TYPE:
- case VECTTYPE:
- case CLOSTYPE:
- case CONTTYPE:
- case CODETYPE:
- case FREETYPE:
- case PORTTYPE:
- case ENVTYPE:
- put_ptr( newpage, 0, FREETYPE, psize[newpage] );
- nextcell[newpage] = 0;
- break;
- #ifdef VMDEBUG
- default:
- zprintf("[VM INTERNAL ERROR] alloc_page: Invalid type: %d\n", type);
- #endif
- }
-
- /* re-define page attributes and type (GC thinks this is a free page) */
- attrib[newpage] = pageattr[type/2];
- ptype[newpage] = type;
-
- return newpage;
- }
-
- #define ALLOCMETHODS 3
- void (*allocstub[ALLOCMETHODS])() = { garbage, gcsquish, out_of_memory };
-
- /************************************************************************/
- /* Allocate a List Cell */
- /* */
- /* Note: this routine will always return a list cell unless */
- /* memory is exhausted, in which case Scheme terminates */
- /* abnormally */
- /************************************************************************/
- int find_list_cell(REGPTR reg)
- {
- while( (reg->disp = nextcell[listpage]) == END_LIST )
- if( (listpage = pagelink[listpage]) == END_LIST )
- if ((listpage = alloc_page(LISTTYPE, 0)) == END_LIST)
- {
- listpage = 0; /* just point to page 0 - null list */
- return 0; /* failed */
- }
-
- reg->page = ADJPAGE(listpage);
- nextcell[listpage] = scheme2c(listpage,reg->disp)->list.free.next;
-
- return 1;
- }
-
- void alloc_list_cell(REGPTR reg)
- {
- for( int i = 0; i < ALLOCMETHODS; i++ )
- {
- if( find_list_cell(reg) )
- return;
- reg->page = ADJPAGE(NIL_PAGE); /* legitimize pointer before GC */
- allocstub[i]();
- }
- }
-
- /************************************************************************/
- /* Allocate a Flonum */
- /* Note: this routine will always return a flonum cell unless */
- /* memory is exhausted, in which case Scheme terminates */
- /* abnormally */
- /************************************************************************/
- int find_flonum(REGPTR reg)
- {
- FLONUM far *f;
-
- if( flopage == END_LIST )
- if( (flopage = alloc_page(FLOTYPE, 0)) == END_LIST )
- return 0;
-
- while( (reg->disp = nextcell[flopage]) == END_LIST )
- if( (flopage = pagelink[flopage]) == END_LIST )
- if( (flopage = alloc_page(FLOTYPE, 0)) == END_LIST )
- return 0; /* failed */
-
- reg->page = ADJPAGE(flopage);
- f = ®2c(reg)->flonum;
-
- nextcell[flopage] = f->next;
- f->type = FLOTYPE;
-
- return 1;
- }
-
- void alloc_flonum( REGPTR reg, double value )
- {
- if (value == 0.0 || value == 1.0 || value == -1.0)
- {
- reg->page = ADJPAGE(SPECFLO);
- reg->disp = sizeof(FLONUM) * (value + 1);
- return;
- }
- for( int i = 0; i < ALLOCMETHODS; i++ )
- {
- if( find_flonum(reg) )
- {
- reg2c(reg)->flonum.data = value;
- return;
- }
- reg->page = ADJPAGE(NIL_PAGE); /* legitimize pointer before GC */
- allocstub[i]();
- }
- }
-
- /************************************************************************/
- /* Allocate String Constant */
- /************************************************************************/
- void alloc_string(REGPTR reg, char *string)
- {
- alloc_block( reg, STRTYPE, strlen(string) );
- put_str( string, CORRPAGE(reg->page), reg->disp );
- }
-
- /**************************************************************************/
- /* Find a big block in Scheme's memory */
- /**************************************************************************/
- unsigned find_big_block(unsigned size)
- {
- unsigned lastpage = NUMPAGES - emspages, page;
-
- char isfree[NUMPAGES];
-
- /* Initialize isfree table */
- for( page = 0; page < NUMPAGES; page++ )
- isfree[page] = 0;
-
- /* Record the number of all free pages */
- for( page = freepage; page != END_LIST; page = pagelink[page] )
- isfree[page] = 1;
-
- for( page = DEDPAGES; page < lastpage; page++ )
- if( isfree[page] ) /* candidate */
- {
- unsigned cursize = 0;
-
- for( int i = page; i < lastpage && isfree[i]; i++ )
- if( (cursize += psize[i]) >= size ) /* that's enough */
- {
- isfree[page] = 0;
- psize[page] = cursize;
- while( i > page ) /* we lose these pages */
- {
- psize[i] = 0;
- attrib[i].FLAGS.nomemory = 1;
- isfree[i--] = 0;
- }
-
- for( freepage = END_LIST, i = lastpage-1; i >= DEDPAGES; i-- )
- if( isfree[i] )
- pagelink[i] = freepage, freepage = i;
-
- return page;
- }
- }
- return 0xffff; /* no pages found */
- }
-
- /************************************************************************/
- /* Allocate a Large Block in Scheme's Memory */
- /************************************************************************/
- void alloc_big_block(REGPTR reg, unsigned type, unsigned size)
- {
- unsigned page;
-
- for( int i = 0; i < ALLOCMETHODS; i++ )
- if( (page = find_big_block(size)) == 0xffff )
- allocstub[i]();
- else break;
-
- zero_page(page);
- put_ptr( page, 0, type/2, size );
- nextcell[page] = END_LIST;
- if( size <= psize[page] - BLK_OVHD )
- {
- put_ptr( page, size, FREETYPE, psize[page] - size );
- nextcell[page] = size;
- }
- ptype[page] = type;
- attrib[page] = pageattr[type/2];
- pagelink[page] = pagelist[type/2];
- pagelist[type/2] = page;
-
- reg->page = ADJPAGE(page);
- reg->disp = 0;
- }
-
- /************************************************************************/
- /* Register class definitions */
- /************************************************************************/
- REG *REG::first = NULL;
-
- void REG::mark(void) /* mark all registers */
- {
- REG *current = first;
-
- while( current ) {
- gcmark( current->page, current->disp );
- current = current->next;
- }
- }
-
- void REG::relocate(void) /* relocate all registers */
- {
- REG *current = first;
-
- while( current ) {
- rel_reg( current );
- current = current->next;
- }
- }
-
- int REG::check(void) /* check consistency */
- {
- REG *current = first;
-
- while( current ) {
- register pg = current->page;
-
- if( pg & 1 )
- return 1;
- else
- pg = CORRPAGE(pg);
-
- if( pg != SPECFIX && pg != SPECCHAR &&
- ( pg >= nextpage || current->disp >= psize[pg] ) )
- return 1;
-
- current = current->next;
- }
- return 0;
- }
-
- void REG::cleanup(REG *low, REG *high) /* selective destructor */
- {
- REG *current = first;
-
- do { // last allocated object ?
- if( low <= current && current < high )
- first = current->next;
- } while( first == (current = current->next) );
-
- current = first;
-
- while( current->next ) {
- if( low <= current->next && current->next < high )
- current->next = current->next->next;
-
- current = current->next;
- }
- }
-
- REG::~REG(void) /* the destructor */
- {
- if( first == this ) // last allocated object ?
- first = next;
- else {
- REG *current = first;
-
- while( current ) {
- if( current->next == this ) {
- current->next = next;
- break;
- }
- current = current->next;
- }
- }
- }
-
- /************************************************************************/
- /* Scheme static registers */
- /************************************************************************/
-
- REG nil_reg ( NIL_DISP, NIL_PAGE*2 ); // nil register reference
- REG fnv_reg ( NIL_DISP, NIL_PAGE*2 ); // Fluid Environment Pointer
- REG gnv_reg ( 0, ENV_PAGE*2 ) ; // Global Environment Pointer
- REG fnv_save ( NIL_DISP, NIL_PAGE*2 );// fluid enviornment pointer save area
- REG stl_save ( NIL_DISP, NIL_PAGE*2 );// scheme-top-level value save area
- REG cb_reg ( 0, SPECCODE*2 ) ; // Code Base Pointer
- REG prev_reg ( NIL_DISP, NIL_PAGE*2 );// pointer to previous stack segment
- REG tmp_reg ( NIL_DISP, NIL_PAGE*2 );
- REG tm2_reg ( NIL_DISP, NIL_PAGE*2 );
- REG trns_reg ( NIL_DISP, NIL_PAGE*2 ); // Transcript File pointer
- REG port_reg ( NIL_DISP, NIL_PAGE*2 );
- REG console_reg ( NIL_DISP, NIL_PAGE*2 );
- REG macro_reg ( NIL_DISP, NIL_PAGE*2 ); // Macro key continuation pointer
- REG quote_reg ( NIL_DISP, NIL_PAGE*2 ); //Storage for interned symbol 'quote
-
- /************************************************************************/
- /* Invoke garbage collection */
- /************************************************************************/
- int compact_every = 7;
- int gc_count = 0;
- void garbage(void)
- {
- gc_on(0); /* display "Garbage Collecting" message */
- gc_count++;
- mark();
- gc_oht(); /* clean up the object hash table */
- gcsweep();
- if (listpage == END_LIST)
- listpage = 0;
- gc_off(); /* un-display "garbage collection" message */
-
- if (!(gc_count % compact_every))
- gcsquish();
- }
-
- /* mark everything pointed to for the garbage collector */
- void mark(void)
- {
- unsigned i;
-
- /* mark all objects pointed to by the Scheme VM's registers */
- for (i = 0; i < NUM_REGS; i++ )
- gcmark(regs[i].page, regs[i].disp);
-
- /* mark all objects pointed by active registers */
- REG::mark();
-
- /* preserve everything pointed to by active stack entries */
- for (i = 0; i <= topofstack / sizeof(POINTER); i++)
- gcmark(s_stack[i].page, s_stack[i].disp);
-
- /* preserve everything pointed to by the oblist */
- for (i = 0; i < HT_SIZE; i++)
- if (hash_page[i])
- gcmark(hash_page[i], hash_disp[i]);
-
- /* preserve everything pointed to by the property list */
- for (i = 0; i < HT_SIZE; i++)
- if (prop_page[i])
- gcmark(prop_page[i], prop_disp[i]);
- }
-
- /************************************************************************/
- /* Memory Exhausted-- Attempt to Perform SCHEME-RESET */
- /************************************************************************/
- void out_of_memory(void)
- {
- int i;
-
- if( nextpage < lastpage && nextpage < NUMPAGES )
- {
- freepage = nextpage;
- for( i = 0; i < 8 && nextpage < (NUMPAGES - 1); i++ )
- {
- pagelink[nextpage] = nextpage + 1;
- attrib[nextpage++].FLAGS.nomemory = 1;
- }
- pagelink[nextpage - 1] = END_LIST;
- } else {
- zprintf("\n[VM ERROR encountered!] Out of memory, attempting to execute SCHEME-RESET\n"
- "[Returning to top level]\n");
- force_reset();
- }
- }
-
- /************************************************************************/
- /* Print Message and Exit Scheme */
- /************************************************************************/
- void print_and_exit( char *msg )
- {
- zprintf( msg );
- GETCH();
- exit( 0xff );
- }
-
- /************************************************************************/
- /* TIPC Scheme '84 Free Space */
- /* */
- /* Purpose: This Routine will return the number of bytes of free */
- /* user memory. */
- /************************************************************************/
- unsigned long freesp(void)
- {
- unsigned space[NUMPAGES]; /* Free memory per page array */
- int i;
- unsigned long bytes_free; /* word to sum bytes available */
-
- sum_space(space);
- bytes_free = 0;
-
- for (i = DEDPAGES; i < lastpage; i++)
- if (ptype[i] == FREETYPE)
- bytes_free += psize[i];
- else
- bytes_free += space[i];
-
- return (bytes_free);
- }